home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2005 October / PCWOCT05.iso / Software / FromTheMag / XAMPP 1.4.14 / xampp-win32-1.4.14-installer.exe / xampp / php / pear / Services / Weather / Weatherdotcom.php < prev   
Encoding:
PHP Script  |  2004-10-01  |  22.6 KB  |  570 lines

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2004 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.0 of the PHP license,       |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available through the world-wide-web at                              |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Alexander Wirtz <alex@pc4p.net>                             |
  17. // +----------------------------------------------------------------------+
  18. //
  19. // $Id: Weatherdotcom.php,v 1.43 2004/07/10 11:12:44 eru Exp $
  20.  
  21. /**
  22. * @package      Services_Weather
  23. * @filesource
  24. */
  25.  
  26. /**
  27. */
  28. require_once "Services/Weather/Common.php";
  29.  
  30. // {{{ class Services_Weather_Weatherdotcom
  31. /**
  32. * PEAR::Services_Weather_Weatherdotcom
  33. *
  34. * This class acts as an interface to the xml service of weather.com. It
  35. * searches for given locations and retrieves current weather data as well
  36. * as forecast for up to 10 days.
  37. *
  38. * For using the weather.com xml-service please visit
  39. *     http://www.weather.com/services/xmloap.html
  40. * and follow the link to sign up, it's free! You will receive an email
  41. * where to download the SDK with the needed images and guidelines how to
  42. * publish live data from weather.com. Unfortunately the guidelines are a
  43. * bit harsh, that's why there's no actual data-representation in this
  44. * class, just the raw data. Also weather.com demands active caching, so I'd
  45. * strongly recommend enabling the caching implemented in this class. It
  46. * obeys to the times as written down in the guidelines.
  47. *
  48. * For working examples, please take a look at
  49. *     docs/Services_Weather/examples/weather.com-basic.php
  50. *     docs/Services_Weather/examples/weather.com-extensive.php
  51. *
  52. * @author       Alexander Wirtz <alex@pc4p.net>
  53. * @link         http://www.weather.com/services/xmloap.html
  54. * @example      examples/weather.com-basic.php      weather.com-basic.php
  55. * @example      examples/weather.com-extensive.php  weather.com-extensive.php
  56. * @package      Services_Weather
  57. * @license      http://www.php.net/license/2_02.txt
  58. * @version      1.3
  59. */
  60. class Services_Weather_Weatherdotcom extends Services_Weather_Common {
  61.  
  62.     // {{{ properties
  63.     /**
  64.     * Partner-ID at weather.com
  65.     *
  66.     * @var      string                      $_partnerID
  67.     * @access   private
  68.     */
  69.     var $_partnerID = "";
  70.  
  71.     /**
  72.     * License key at weather.com
  73.     *
  74.     * @var      string                      $_licenseKey
  75.     * @access   private
  76.     */
  77.     var $_licenseKey = "";
  78.  
  79.     /**
  80.     * Object containing the promotional links-data
  81.     *
  82.     * @var      object stdClass             $_links
  83.     * @access   private
  84.     */
  85.     var $_links;
  86.  
  87.     /**
  88.     * XML_Unserializer, used for processing the xml
  89.     *
  90.     * @var      object XML_Unserializer     $_unserializer
  91.     * @access   private
  92.     */
  93.     var $_unserializer;
  94.     // }}}
  95.  
  96.     // {{{ constructor
  97.     /**
  98.     * Constructor
  99.     *
  100.     * Requires XML_Serializer to be installed
  101.     *
  102.     * @param    array                       $options
  103.     * @param    mixed                       $error
  104.     * @throws   PEAR_Error
  105.     * @see      Science_Weather::Science_Weather
  106.     * @access   private
  107.     */
  108.     function Services_Weather_Weatherdotcom($options, &$error)
  109.     {
  110.         $perror = null;
  111.         $this->Services_Weather_Common($options, $perror);
  112.         if (Services_Weather::isError($perror)) {
  113.             $error = $perror;
  114.             return;
  115.         }
  116.  
  117.         // Set options accordingly
  118.         if (isset($options["partnerID"])) {
  119.             $this->setAccountData($options["partnerID"]);
  120.         }
  121.         if (isset($options["licenseKey"])) {
  122.             $this->setAccountData("", $options["licenseKey"]);
  123.         }
  124.         
  125.         include_once "XML/Unserializer.php";
  126.         $unserializer = &new XML_Unserializer(array("complexType" => "object", "keyAttribute" => "type"));
  127.         if (Services_Weather::isError($unserializer)) {
  128.             $error = $unserializer;
  129.             return;
  130.         } else {
  131.             $this->_unserializer = $unserializer;
  132.         }
  133.         
  134.         // Can't acquire an object here, has to be clean on every request
  135.         include_once "HTTP/Request.php";
  136.     }
  137.     // }}}
  138.  
  139.     // {{{ setAccountData()
  140.     /**
  141.     * Sets the neccessary account-information for weather.com, you'll
  142.     * receive them after registering for the XML-stream
  143.     *
  144.     * @param    string                      $partnerID
  145.     * @param    string                      $licenseKey
  146.     * @access   public
  147.     */
  148.     function setAccountData($partnerID, $licenseKey)
  149.     {
  150.         if (strlen($partnerID) && ctype_digit($partnerID)) {
  151.             $this->_partnerID  = $partnerID;
  152.         }
  153.         if (strlen($licenseKey) && ctype_alnum($licenseKey)) {
  154.             $this->_licenseKey = $licenseKey;
  155.         }
  156.     }
  157.     // }}}
  158.  
  159.     // {{{ _checkLocationID()
  160.     /**
  161.     * Checks the id for valid values and thus prevents silly requests to
  162.     * weather.com server
  163.     *
  164.     * @param    string                      $id
  165.     * @return   PEAR_Error|bool
  166.     * @throws   PEAR_Error::SERVICES_WEATHER_ERROR_NO_LOCATION
  167.     * @throws   PEAR_Error::SERVICES_WEATHER_ERROR_INVALID_LOCATION
  168.     * @access   private
  169.     */
  170.     function _checkLocationID($id)
  171.     {
  172.         if (is_array($id) || is_object($id) || !strlen($id)) {
  173.             return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_NO_LOCATION, __FILE__, __LINE__);
  174.         } elseif (!ctype_alnum($id) || (strlen($id) > 8)) {
  175.             return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_INVALID_LOCATION, __FILE__, __LINE__);
  176.         }
  177.  
  178.         return true;
  179.     }
  180.     // }}}
  181.  
  182.     // {{{ _parseWeatherData()
  183.     /**
  184.     * Parses the data returned by the provided URL and caches it
  185.     *
  186.     * @param    string                      $id
  187.     * @param    string                      $url
  188.     * @return   PEAR_Error|bool
  189.     * @throws   PEAR_Error::SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA
  190.     * @throws   PEAR_Error
  191.     * @access   private
  192.     */
  193.     function _parseWeatherData($id, $url)
  194.     {
  195.         // Get data from URL...
  196.         $request = &new HTTP_Request($url, array("timeout" => $this->_httpTimeout));
  197.         $status = $request->sendRequest();
  198.         if (Services_Weather::isError($status)) {
  199.             return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA, __FILE__, __LINE__);
  200.         }
  201.         $data = $request->getResponseBody();
  202.         
  203.         // ...and unserialize
  204.         $status = $this->_unserializer->unserialize($data);
  205.  
  206.         if (Services_Weather::isError($status)) {
  207.             return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA, __FILE__, __LINE__);
  208.         } else {
  209.             $root = $this->_unserializer->getRootName();
  210.             $data = $this->_unserializer->getUnserializedData();
  211.  
  212.             if (Services_Weather::isError($root)) {
  213.                 // Something wrong here...
  214.                 return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA, __FILE__, __LINE__);
  215.             } elseif ($root == "error") {
  216.                 // We got an error back from weather.com
  217.                 $errno  = key(get_object_vars($data));
  218.                 return Services_Weather::raiseError($errno, __FILE__, __LINE__);
  219.             } else {
  220.                 // Valid data, lets get started
  221.                 // Loop through the different sub-parts of the data fro processing
  222.                 foreach (get_object_vars($data) as $key => $val) {
  223.                     switch ($key) {
  224.                         case "head":
  225.                             continue 2;
  226.                             break;
  227.                         case "prmo":
  228.                             $varname  = "links";
  229.                             break;
  230.                         case "loc":
  231.                             $varname  = "location";
  232.                             break;
  233.                         case "cc":
  234.                             $varname  = "weather";
  235.                             break;
  236.                         case "dayf":
  237.                             $varname  = "forecast";
  238.                             break;
  239.                     }
  240.                     // Save data in object
  241.                     $this->{"_".$varname} = $val;
  242.                     if ($this->_cacheEnabled) {
  243.                         // ...and cache if possible
  244.                         $expire = constant("SERVICES_WEATHER_EXPIRES_".strtoupper($varname));
  245.                         $this->_cache->extSave($id, $val, "", $expire, $varname);
  246.                     }
  247.                 }
  248.             }
  249.         }
  250.  
  251.         return true;
  252.     }
  253.     // }}}
  254.  
  255.     // {{{ searchLocation()
  256.     /**
  257.     * Searches IDs for given location, returns array of possible locations
  258.     * or single ID
  259.     *
  260.     * @param    string                      $location
  261.     * @param    bool                        $useFirst       If set, first ID of result-array is returned
  262.     * @return   PEAR_Error|array|string
  263.     * @throws   PEAR_Error::SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA
  264.     * @throws   PEAR_Error::SERVICES_WEATHER_ERROR_UNKNOWN_LOCATION
  265.     * @access   public
  266.     */
  267.     function searchLocation($location, $useFirst = false)
  268.     {
  269.         // Get search data from server and unserialize
  270.         $searchURL = "http://xoap.weather.com/search/search?where=".urlencode(trim($location));
  271.         $status = $this->_unserializer->unserialize($searchURL, true, array("overrideOptions" => true, "complexType" => "array", "keyAttribute" => "id"));
  272.  
  273.         if (Services_Weather::isError($status)) {
  274.             return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA, __FILE__, __LINE__);
  275.         } else {
  276.             $search = $this->_unserializer->getUnserializedData();
  277.  
  278.             if (Services_Weather::isError($search)) {
  279.                 return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA, __FILE__, __LINE__);
  280.             } elseif (!is_array($search) || !sizeof($search)) {
  281.                 return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_UNKNOWN_LOCATION, __FILE__, __LINE__);
  282.             } else {
  283.                 if (!$useFirst && (sizeof($search) > 1)) {
  284.                     $searchReturn = $search;
  285.                 } elseif ($useFirst || (sizeof($search) == 1)) {
  286.                     $searchReturn = key($search);
  287.                 }
  288.             }
  289.         }
  290.  
  291.         return $searchReturn;
  292.     }
  293.     // }}}
  294.  
  295.     // {{{ searchLocationByCountry()
  296.     /**
  297.     * Returns only false, as weather.com offers no country listing via 
  298.     * its XML services 
  299.     *
  300.     * @param    string                      $country
  301.     * @return   bool
  302.     * @access   public
  303.     * @deprecated
  304.     */
  305.     function searchLocationByCountry($country = "")
  306.     {
  307.         return false;
  308.     }
  309.     // }}}
  310.  
  311.     // {{{ getLinks()
  312.     /**
  313.     * Returns the data for the promotional links belonging to the ID
  314.     *
  315.     * @param    string                      $id
  316.     * @return   PEAR_Error|array
  317.     * @throws   PEAR_Error
  318.     * @access   public
  319.     */
  320.     function getLinks($id = "")
  321.     {
  322.         $status = $this->_checkLocationID($id);
  323.  
  324.         if (Services_Weather::isError($status)) {
  325.             return $status;
  326.         }
  327.  
  328.         $linksReturn = array();
  329.         $linksURL    = "http://xoap.weather.com/weather/local/".$id."?prod=xoap&par=".$this->_partnerID."&key=".$this->_licenseKey."&link=xoap";
  330.  
  331.         if ($this->_cacheEnabled && ($links = $this->_cache->get($id, "links"))) {
  332.             // Get data from cache
  333.             $this->_links = $links;
  334.             $linksReturn["cache"] = "HIT";
  335.         } else {
  336.             // Same as in the function above...
  337.             $status = $this->_parseWeatherData($id, $linksURL);
  338.  
  339.             if (Services_Weather::isError($status)) {
  340.                 return $status;
  341.             }
  342.             $linksReturn["cache"] = "MISS";
  343.         }
  344.  
  345.         $linksReturn["promo"] = array();
  346.         for ($i = 0; $i < sizeof($this->_links->link); $i++) {
  347.             $linksReturn["promo"][$i] = array();
  348.             $linksReturn["promo"][$i]["title"] = $this->_links->link[$i]->t;
  349.             // B0rked response (returned is &par=xoap, should be &prod=xoap), fix it
  350.             $linksReturn["promo"][$i]["link"]  = str_replace("par=", "prod=", $this->_links->link[$i]->l);
  351.             $linksReturn["promo"][$i]["link"] .= "&par=".$this->_partnerID;
  352.         }   
  353.  
  354.         return $linksReturn;
  355.     }
  356.     // }}}
  357.  
  358.     // {{{ getLocation()
  359.     /**
  360.     * Returns the data for the location belonging to the ID
  361.     *
  362.     * @param    string                      $id
  363.     * @return   PEAR_Error|array
  364.     * @throws   PEAR_Error
  365.     * @access   public
  366.     */
  367.     function getLocation($id = "")
  368.     {
  369.         $status = $this->_checkLocationID($id);
  370.  
  371.         if (Services_Weather::isError($status)) {
  372.             return $status;
  373.         }
  374.  
  375.         $locationReturn = array();
  376.         $locationURL    = "http://xoap.weather.com/weather/local/".$id."?prod=xoap&par=".$this->_partnerID."&key=".$this->_licenseKey;
  377.  
  378.         if ($this->_cacheEnabled && ($location = $this->_cache->get($id, "location"))) {
  379.             // Get data from cache
  380.             $this->_location = $location;
  381.             $locationReturn["cache"] = "HIT";
  382.         } else {
  383.             // Same as in the function above...
  384.             $status = $this->_parseWeatherData($id, $locationURL);
  385.  
  386.             if (Services_Weather::isError($status)) {
  387.                 return $status;
  388.             }
  389.             $locationReturn["cache"] = "MISS";
  390.         }
  391.  
  392.         $locationReturn["name"]      = $this->_location->dnam;
  393.         $locationReturn["time"]      = date($this->_timeFormat, strtotime($this->_location->tm));
  394.         $locationReturn["latitude"]  = $this->_location->lat;
  395.         $locationReturn["longitude"] = $this->_location->lon;
  396.         $locationReturn["sunrise"]   = date($this->_timeFormat, strtotime($this->_location->sunr));
  397.         $locationReturn["sunset"]    = date($this->_timeFormat, strtotime($this->_location->suns));
  398.         $locationReturn["timezone"]  = $this->_location->zone;
  399.  
  400.         return $locationReturn;
  401.     }
  402.     // }}}
  403.  
  404.     // {{{ getWeather()
  405.     /**
  406.     * Returns the weather-data for the supplied location
  407.     *
  408.     * @param    string                      $id
  409.     * @param    string                      $unitsFormat
  410.     * @return   PEAR_Error|array
  411.     * @throws   PEAR_Error
  412.     * @access   public
  413.     */
  414.     function getWeather($id = "", $unitsFormat = "")
  415.     {
  416.         $status = $this->_checkLocationID($id);
  417.  
  418.         if (Services_Weather::isError($status)) {
  419.             return $status;
  420.         }
  421.  
  422.         // Get other data
  423.         $units    = $this->getUnitsFormat($unitsFormat);
  424.  
  425.         $weatherReturn = array();
  426.         $weatherURL    = "http://xoap.weather.com/weather/local/".$id."?cc=*&prod=xoap&par=".$this->_partnerID."&key=".$this->_licenseKey."&unit=s";
  427.  
  428.         if ($this->_cacheEnabled && ($weather = $this->_cache->get($id, "weather"))) {
  429.             // Same procedure...
  430.             $this->_weather = $weather;
  431.             $weatherReturn["cache"] = "HIT";
  432.         } else {
  433.             // ...as last function
  434.             $status = $this->_parseWeatherData($id, $weatherURL);
  435.  
  436.             if (Services_Weather::isError($status)) {
  437.                 return $status;
  438.             }
  439.             $weatherReturn["cache"] = "MISS";
  440.         }
  441.         
  442.         // Some explanation for the next two lines:
  443.         // weather.com isn't always supplying the timezone in the update string, but
  444.         // uses "Local Time" as reference, which is imho utterly stupid, because it's
  445.         // inconsistent. Well, what I do here is check for this string and if I can
  446.         // find it, I calculate the difference between the timezone at the location
  447.         // and this computers timezone. This amount of seconds is then subtracted from
  448.         // the time the update-string has delivered.
  449.         $update   = str_replace("Local Time", "", $this->_weather->lsup);
  450.         $adjustTZ = ($update == $this->_weather->lsup) ? 0 : $this->_location->zone * 3600 - date("Z");
  451.         $weatherReturn["update"]            = gmdate(trim($this->_dateFormat." ".$this->_timeFormat), strtotime($update) - $adjustTZ);
  452.         $weatherReturn["updateRaw"]         = $this->_weather->lsup;
  453.         $weatherReturn["station"]           = $this->_weather->obst;
  454.         $weatherReturn["temperature"]       = $this->convertTemperature($this->_weather->tmp, "f", $units["temp"]);
  455.         $weatherReturn["feltTemperature"]   = $this->convertTemperature($this->_weather->flik, "f", $units["temp"]);
  456.         $weatherReturn["condition"]         = $this->_weather->t;
  457.         $weatherReturn["conditionIcon"]     = $this->_weather->icon;
  458.         $weatherReturn["pressure"]          = $this->convertPressure($this->_weather->bar->r, "in", $units["pres"]);
  459.         $weatherReturn["pressureTrend"]     = $this->_weather->bar->d;
  460.         $weatherReturn["wind"]              = $this->convertSpeed($this->_weather->wind->s, "mph", $units["wind"]);
  461.         $weatherReturn["windGust"]            = $this->convertSpeed($this->_weather->wind->gust, "mph", $units["wind"]);        
  462.         $weatherReturn["windDegrees"]       = $this->_weather->wind->d;
  463.         $weatherReturn["windDirection"]     = $this->_weather->wind->t;
  464.         $weatherReturn["humidity"]          = $this->_weather->hmid;
  465.         if (is_numeric($this->_weather->vis)) {
  466.             $weatherReturn["visibility"]    = $this->convertDistance($this->_weather->vis, "sm", $units["vis"]);
  467.         } else {
  468.             $weatherReturn["visibility"]    = $this->_weather->vis;
  469.         }
  470.         $weatherReturn["uvIndex"]           = $this->_weather->uv->i;
  471.         $weatherReturn["uvText"]            = $this->_weather->uv->t;
  472.         $weatherReturn["dewPoint"]          = $this->convertTemperature($this->_weather->dewp, "f", $units["temp"]);
  473.  
  474.         return $weatherReturn;
  475.     }
  476.     // }}}
  477.  
  478.     // {{{ getForecast()
  479.     /**
  480.     * Get the forecast for the next days
  481.     *
  482.     * @param    string                      $id
  483.     * @param    int                         $days           Values between 1 and 10
  484.     * @param    string                      $unitsFormat
  485.     * @return   PEAR_Error|array
  486.     * @throws   PEAR_Error
  487.     * @access   public
  488.     */
  489.     function getForecast($id = "", $days = 2, $unitsFormat = "")
  490.     {
  491.         $status = $this->_checkLocationID($id);
  492.  
  493.         if (Services_Weather::isError($status)) {
  494.             return $status;
  495.         }
  496.         if (!in_array($days, range(1, 10))) {
  497.             $days = 2;
  498.         }
  499.         
  500.         // Get other data
  501.         $units    = $this->getUnitsFormat($unitsFormat);
  502.  
  503.         $forecastReturn = array();
  504.         $forecastURL = "http://xoap.weather.com/weather/local/".$id."?dayf=10&prod=xoap&par=".$this->_partnerID."&key=".$this->_licenseKey."&unit=s";
  505.  
  506.         if ($this->_cacheEnabled && ($forecast = $this->_cache->get($id, "forecast"))) {
  507.             // Encore...
  508.             $this->_forecast = $forecast;
  509.             $forecastReturn["cache"] = "HIT";
  510.         } else {
  511.             // ...
  512.             $status = $this->_parseWeatherData($id, $forecastURL, $days);
  513.  
  514.             if (Services_Weather::isError($status)) {
  515.                 return $status;
  516.             }
  517.             $forecastReturn["cache"] = "MISS";
  518.         }
  519.  
  520.         // Some explanation for the next two lines: (same as above)
  521.         // weather.com isn't always supplying the timezone in the update string, but
  522.         // uses "Local Time" as reference, which is imho utterly stupid, because it's
  523.         // inconsistent. Well, what I do here is check for this string and if I can
  524.         // find it, I calculate the difference between the timezone at the location
  525.         // and this computers timezone. This amount of seconds is then subtracted from
  526.         // the time the update-string has delivered.
  527.         $update   = str_replace("Local Time", "", $this->_forecast->lsup);
  528.         $adjustTZ = ($update == $this->_forecast->lsup) ? 0 : $this->_location->zone * 3600 - date("Z");
  529.         $forecastReturn["update"]    = gmdate($this->_dateFormat." ".$this->_timeFormat, strtotime($update) - $adjustTZ);
  530.         $forecastReturn["updateRaw"] = $this->_forecast->lsup;
  531.         $forecastReturn["days"]      = array();
  532.  
  533.         for ($i = 0; $i < $days; $i++) {
  534.             $day = array(
  535.                 "temperatureHigh" => $this->convertTemperature($this->_forecast->day[$i]->hi, "f", $units["temp"]),
  536.                 "temperatureLow"  => $this->convertTemperature($this->_forecast->day[$i]->low, "f", $units["temp"]),
  537.                 "sunrise"         => date($this->_timeFormat, strtotime($this->_forecast->day[$i]->sunr)),
  538.                 "sunset"          => date($this->_timeFormat, strtotime($this->_forecast->day[$i]->suns)),
  539.                 "day" => array(
  540.                     "condition"     => $this->_forecast->day[$i]->part[0]->t,
  541.                     "conditionIcon" => $this->_forecast->day[$i]->part[0]->icon,
  542.                     "wind"          => $this->convertSpeed($this->_forecast->day[$i]->part[0]->wind->s, "mph", $units["wind"]),
  543.                     "windGust"      => $this->convertSpeed($this->_forecast->day[$i]->part[0]->wind->gust, "mph", $units["wind"]),
  544.                     "windDegrees"   => $this->_forecast->day[$i]->part[0]->wind->d,
  545.                     "windDirection" => $this->_forecast->day[$i]->part[0]->wind->t,
  546.                     "precipitation" => $this->_forecast->day[$i]->part[0]->ppcp,
  547.                     "humidity"      => $this->_forecast->day[$i]->part[0]->hmid
  548.                 ),
  549.                 "night" => array (
  550.                     "condition"     => $this->_forecast->day[$i]->part[1]->t,
  551.                     "conditionIcon" => $this->_forecast->day[$i]->part[1]->icon,
  552.                     "wind"          => $this->convertSpeed($this->_forecast->day[$i]->part[1]->wind->s, "mph", $units["wind"]),
  553.                     "windGust"      => $this->convertSpeed($this->_forecast->day[$i]->part[1]->wind->gust, "mph", $units["wind"]),
  554.                     "windDegrees"   => $this->_forecast->day[$i]->part[1]->wind->d,
  555.                     "windDirection" => $this->_forecast->day[$i]->part[1]->wind->t,
  556.                     "precipitation" => $this->_forecast->day[$i]->part[1]->ppcp,
  557.                     "humidity"      => $this->_forecast->day[$i]->part[1]->hmid
  558.                 )
  559.             );
  560.  
  561.             $forecastReturn["days"][] = $day;
  562.         }
  563.  
  564.         return $forecastReturn;
  565.     }
  566.     // }}}
  567. }
  568. // }}}
  569. ?>
  570.